import Callout from 'components/Callout';
import PartnerContentLink from 'components/PartnerContentLink';
import Details from 'components/Details';

# Date and time formatting

The formatting of dates and times varies greatly between locales (e.g. "Apr 24, 2023" in `en-US` vs. "24 квіт. 2023 р." in `uk-UA`). By using the formatting capabilities of `next-intl`, you can handle i18n differences in your Next.js app automatically.

## Formatting dates and times [#dates-times]

You can format plain dates that are not part of a message with the `dateTime` function that is returned from the `useFormatter` hook:

```js
import {useFormatter} from 'next-intl';

function Component() {
  const format = useFormatter();
  const dateTime = new Date('2020-11-20T10:36:01.516Z');

  // Renders "Nov 20, 2020"
  format.dateTime(dateTime, {
    year: 'numeric',
    month: 'short',
    day: 'numeric'
  });

  // Renders "11:36 AM"
  format.dateTime(dateTime, {hour: 'numeric', minute: 'numeric'});
}
```

See [the MDN docs about `DateTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#Using_options) to learn more about the options that you can provide to the `dateTime` function or try [the interactive explorer for `Intl.DateTimeFormat`](https://www.intl-explorer.com/DateTimeFormat).

If you have [global formats](/docs/usage/configuration#formats) configured, you can reference them by passing a name as the second argument:

```js
format.dateTime(dateTime, 'short');
```

<Details id="parsing-manipulation">
<summary>How can I parse dates or manipulate them?</summary>

Since `next-intl` is only concerned with formatting dates, you can use a library like [date-fns](https://date-fns.org/) to manipulate them.

To parse dates, you can pass them to [the `Date` constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date).

```tsx
import {subDays} from 'date-fns';

// Make sure your date string conforms to ISO 8601
const date = new Date('2020-11-20T10:36:01.516Z');

// 2020-11-18T10:36:01.516Z
const twoDaysAgo = subDays(date, 2);
```

</Details>

## Formatting relative times [#relative-times]

You can format plain dates that are not part of a message with the `relativeTime` function:

```js
import {useFormatter} from 'next-intl';

function Component() {
  const format = useFormatter();
  const dateTime = new Date('2020-11-20T08:30:00.000Z');

  // At 2020-11-20T10:36:00.000Z,
  // this will render "2 hours ago"
  format.relativeTime(dateTime);
}
```

Note that values are rounded, so e.g. if 126 minutes have passed, "2 hours ago" will be returned.

### Supplying `now`

By default, `relativeTime` will use [the global value for `now`](/docs/usage/configuration#now). If you want to use a different value, you can explicitly pass this as the second parameter.

```js
import {useFormatter} from 'next-intl';

function Component() {
  const format = useFormatter();
  const dateTime = new Date('2020-11-20T08:30:00.000Z');
  const now = new Date('2020-11-20T10:36:00.000Z');

  // Renders "2 hours ago"
  format.relativeTime(dateTime, now);
}
```

If you want the relative time value to update over time, you can do so with [the `useNow` hook](/docs/usage/configuration#now):

```js
import {useNow, useFormatter} from 'next-intl';

function Component() {
  // Use the global now value initially …
  const now = useNow({
    // … and update it every 10 seconds
    updateInterval: 1000 * 10
  });

  const format = useFormatter();
  const dateTime = new Date('2020-11-20T10:36:01.516Z');

  // Renders e.g. "2 hours ago" and updates continuously
  format.relativeTime(dateTime, now);
}
```

### Customizing the unit

By default, `relativeTime` will pick a unit based on the difference between the passed date and `now` (e.g. 3 seconds, 40 minutes, 4 days, etc.).

If you want to use a specific unit, you can provide options via the second argument:

```js
import {useFormatter} from 'next-intl';

function Component() {
  const format = useFormatter();
  const dateTime = new Date('2020-03-20T08:30:00.000Z');
  const now = new Date('2020-11-22T10:36:00.000Z');

  // Renders "247 days ago"
  format.relativeTime(dateTime, {now, unit: 'day'});
}
```

## Formatting date and time ranges [#date-time-ranges]

You can format ranges of dates and times with the `dateTimeRange` function:

```js
import {useFormatter} from 'next-intl';

function Component() {
  const format = useFormatter();
  const dateTimeA = new Date('2020-11-20T08:30:00.000Z');
  const dateTimeB = new Date('2021-01-24T08:30:00.000Z');

  // Renders "Nov 20, 2020 – Jan 24, 2021"
  format.dateTimeRange(dateTimeA, dateTimeB, {
    year: 'numeric',
    month: 'short',
    day: 'numeric'
  });
}
```

If you have [global formats](/docs/usage/configuration#formats) configured, you can reference them by passing a name as the trailing argument:

```js
format.dateTimeRange(dateTimeA, dateTimeB, 'short');
```

## Dates and times within messages

Dates and times can be embedded within messages by using the ICU syntax.

```json filename="en.json"
{
  "ordered": "Ordered on {orderDate, date, medium}"
}
```

These formats are supported out of the box: `full`, `long`, `medium` and `short`.

<Callout>

If you work with translators, it can be helpful for them to use an editor that supports the ICU syntax for dates and times (e.g. the <PartnerContentLink name="dates-times-messages" href="https://support.crowdin.com/icu-message-syntax/#date-time">Crowdin Editor</PartnerContentLink>).

</Callout>

You can customize the formatting by using date skeletons:

```json filename="en.json"
{
  // Renders e.g. "Ordered on Jul 9, 2024"
  "ordered": "Ordered on {orderDate, date, ::yyyyMMMd}"
}
```

Note the leading `::` that is used to indicate that a skeleton should be used.

**These formats from ICU are supported:**

| Symbol | Meaning                                | Pattern                                  | Example                                             |
| :----: | :------------------------------------- | ---------------------------------------- | --------------------------------------------------- |
|   G    | Era designator (includes the date)     | G<br/>GGGG<br/>GGGGG                     | 7/9/2024 AD<br/>7/9/2024 Anno Domini<br/>7/9/2024 A |
|   y    | Year                                   | y<br/>yy<br/>yyyy                        | 2024<br/>24<br/>2024                                |
|   M    | Month in year                          | M<br/>MM<br/>MMM<br/>MMMM<br/>MMMMM<br/> | 7<br/>07<br/>Jul<br/>July<br/>J                     |
|   d    | Day in month                           | d<br/>dd                                 | 9<br/>09                                            |
|   E    | Day of week                            | E<br/>EEEE<br/>EEEEE                     | Tue<br/>Tuesday<br/>T                               |
|   h    | Hour (1-12)                            | h<br/>hh                                 | 9 AM<br/>09 AM                                      |
|   K    | Hour (0-11)                            | K<br/>KK                                 | 0 AM (12 AM with `h`)<br/>00 AM                     |
|   H    | Hour (0-23)                            | HH                                       | 09                                                  |
|   k    | Hour (1-24)                            | kk                                       | 24 (00 with `H`)                                    |
|   m    | Minute (2 digits if used with seconds) | m<br/>mmss                               | 6<br/>06:03                                         |
|   s    | Second (2 digits if used with minutes) | s<br/>mmss                               | 3<br/>06:03                                         |
|   z    | Time zone                              | z<br/>zzzz                               | GMT+2<br/>Central European Summer Time              |

Patterns can be combined with each other, therefore e.g. `yyyyMMMd` would return "Jul 9, 2024".

### Custom date and time formats

To use custom formats in messages, you can provide formatters based on [`DateTimeFormat` options](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat#Using_options) that can be referenced by name.

```json filename="en.json"
{
  "ordered": "Ordered on {orderDate, date, short}"
}
```

```js
t(
  'ordered',
  {orderDate: new Date('2020-11-20T10:36:01.516Z')},
  {
    dateTime: {
      short: {
        day: 'numeric',
        month: 'short',
        year: 'numeric'
      }
    }
  }
);
```

<Callout>
  To reuse date and time formats for multiple components, you can configure
  [global formats](/docs/usage/configuration#formats).
</Callout>
